package com.datasecops.scannerservices.db;

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.*;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * MongoDB库相关操作
 *
 * @author: GeXiaoLong
 * @time: 2022/9/30 11:00
 */
@Service
@Slf4j
public class MongoDBUtil {
    private static Logger logger = LoggerFactory.getLogger(MongoDBUtil.class);
    private static MongoClient mongoClient = null;
    //每一批次定1000行
    private static int batchLine = 1000;


    /**
     * 获取MongoDB数据库连接
     *
     * @param host:服务器地址
     * @param port：服务器端口号
     * @param username     用户名
     * @param databaseName 数据库名称
     * @param password     密码
     * @return MongoClient
     */

    public static MongoClient getMongoClient(String host, int port, String username, String databaseName, String password) {

        //连接到MongoDB服务 如果是远程连接可以替换“localhost”为服务器所在IP地址
        //ServerAddress()两个参数分别为 服务器地址 和 端口
        ServerAddress serverAddress = new ServerAddress(host, port);
        List<ServerAddress> addrs = new ArrayList<>();
        addrs.add(serverAddress);

        MongoCredential credential = MongoCredential.createScramSha1Credential(username, databaseName, password.toCharArray());
        List<MongoCredential> credentials = new ArrayList<>();
        credentials.add(credential);
        //通过连接认证获取MongoDB连接
        mongoClient = new MongoClient(addrs, credentials);
        return mongoClient;
    }


    /**
     * MongoDB 获取数据库连接
     *
     * @param mongoClient  MongoDB客户端连接
     * @param host:服务器地址
     * @param port：服务器端口号
     * @param username     用户名
     * @param databaseName 数据库名称
     * @param password     密码
     * @return MongoDatabase
     */

    public static MongoDatabase getMongoDatabase(MongoClient mongoClient, String host, int port, String username, String databaseName, String password) {
        try {
            //连接到数据库
            MongoDatabase mongoDatabase = mongoClient.getDatabase(databaseName);
            logger.info("Connect to database successfully");
            return mongoDatabase;
        } catch (Exception e) {
            logger.error(e.getClass().getName() + ": " + e.getMessage());
        }
        return null;
    }


    /**
     * 创建集合
     * 使用 com.mongodb.client.MongoDatabase 类中的createCollection()来创建集
     *
     * @param host:服务器地址
     * @param port：服务器端口号
     * @param username       用户名
     * @param databaseName   数据库名称
     * @param password       密码
     * @param collectionName 集合名称
     */

    public static void createCollection(String host, int port, String username, String databaseName, String password, String collectionName) {
        try {
            //通过连接认证获取MongoDB连接


            MongoClient mongoClient = getMongoClient(host, port, username, databaseName, password);
            // 连接到数据库
            MongoDatabase mongoDatabase = getMongoDatabase(mongoClient, host, port, username, databaseName, password);
            logger.info("Connect to database successfully");
            mongoDatabase.createCollection(collectionName);
            logger.info("集合创建成功");
            mongoClient.close();
        } catch (Exception e) {
            logger.error(e.getClass().getName() + ": " + e.getMessage());
        }
    }


    /**
     * 获取集合
     * 使用com.mongodb.client.MongoDatabase类的 getCollection() 方法来获取一个集合
     *
     * @param host:服务器地址
     * @param port：服务器端口号
     * @param username       用户名
     * @param databaseName   数据库名称
     * @param password       密码
     * @param collectionName 集合名称
     */
    public static void getCollection(String host, int port, String username, String databaseName, String password, String collectionName) {
        try {
            //通过连接认证获取MongoDB连接
            MongoClient mongoClient = getMongoClient(host, port, username, databaseName, password);
            // 连接到数据库
            MongoDatabase mongoDatabase = getMongoDatabase(mongoClient, host, port, username, databaseName, password);
            logger.info("Connect to database successfully");
            MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName);
            logger.info("集合 test 选择成功");
            collection.count();
            mongoClient.close();
        } catch (Exception e) {
            logger.error(e.getClass().getName() + ": " + e.getMessage());
        }
    }


    /**
     * 插入文档
     * 使用com.mongodb.client.MongoCollection类的 insertMany() 方法来插入一个文档
     *
     * @param host:服务器地址
     * @param port：服务器端口号
     * @param username       用户名
     * @param databaseName   数据库名称
     * @param password       密码
     * @param collectionName 集合名称
     * @param documentMap    请求参数
     */

    public static void addData(String host, int port, String username, String databaseName, String password,
                               String collectionName, Map<String, Object> documentMap) {
        try {
            //通过连接认证获取MongoDB连接
            MongoClient mongoClient = getMongoClient(host, port, username, databaseName, password);
            // 连接到数据库
            MongoDatabase mongoDatabase = getMongoDatabase(mongoClient, host, port, username, databaseName, password);
            logger.info("Connect to database successfully");
            MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName);
            logger.info("集合 test 选择成功");

            //插入文档
            Document document = new Document();
            for (Map.Entry<String, Object> entry : documentMap.entrySet()) {
                document.append(entry.getKey(), entry.getValue());
            }

            List<Document> documents = new ArrayList<Document>();
            documents.add(document);
            collection.insertMany(documents);
            logger.info("文档插入成功");
            mongoClient.close();
        } catch (Exception e) {
            logger.error(e.getClass().getName() + ": " + e.getMessage());
        }
    }


    /**
     * 检索所有文档
     * 使用 com.mongodb.client.MongoCollection 类中的 find() 方法来获取集合中的所有文档。
     *
     * @param host:服务器地址
     * @param port：服务器端口号
     * @param username       用户名
     * @param databaseName   数据库名称
     * @param password       密码
     * @param collectionName 集合名称
     */
    public static List<Document> findAll(String host, int port, String username, String databaseName, String password,
                                         String collectionName) {

        List<Document> list = new ArrayList<>();
        try {
            //通过连接认证获取MongoDB连接
            MongoClient mongoClient = getMongoClient(host, port, username, databaseName, password);
            // 连接到数据库
            MongoDatabase mongoDatabase = getMongoDatabase(mongoClient, host, port, username, databaseName, password);
            logger.info("Connect to database successfully");
            MongoCollection<Document> collection = mongoDatabase.getCollection(collectionName);
            logger.info("集合 test 选择成功");

            FindIterable<Document> findIterable = collection.find();
            for (Document document : findIterable) {
                list.add(document);
            }
            logger.info("数据条数============>" + list.size());
            mongoClient.close();
        } catch (Exception e) {
            logger.error(e.getClass().getName() + ": " + e.getMessage());
        }
        return list;
    }


    /**
     * 检索所有文档
     * 使用 com.mongodb.client.MongoCollection 类中的 find() 方法来获取集合中的所有文档。
     *
     * @param host           :服务器地址
     * @param port           ：服务器端口号
     * @param username       用户名
     * @param databaseName   数据库名称
     * @param password       密码
     * @param collectionName 集合名称
     * @return
     */
    public static LinkedHashMap<String, LinkedList<String>> findAlls(String host, int port, String username, String databaseName, String password,
                                                                     String collectionName) {

        List<String> list = new ArrayList<>();
        LinkedHashMap<String, LinkedList<String>> sourceDataMap = null;
        try {
            //通过连接认证获取MongoDB连接
            // 连接到数据库
            // 定义MongoDB的连接地址
            ServerAddress serverAddress = new ServerAddress(host, port);

            // 定义MongoDB的认证信息
            MongoCredential credential = MongoCredential.createCredential(username, databaseName, password.toCharArray());

            // 定义MongoDB的连接对象
            MongoClient mongoClient = new MongoClient(serverAddress, Arrays.asList(credential));

            // 获取MongoDB的数据库对象
            MongoDatabase database = mongoClient.getDatabase(databaseName);
            /*MongoDatabase mongoDatabase = getDB(host, port, username, databaseName, password);*/
            logger.info("Connect to database successfully");
            MongoCollection<Document> collection = database.getCollection(collectionName);
            logger.info("集合 test 选择成功");
            Long ss = collection.count();
            int i = (int) (ss / batchLine);
            int b = 0;
            int c = 0;
            sourceDataMap = new LinkedHashMap<>();
            while (b <= i) {
                FindIterable<Document> findIterable = collection.find().limit(batchLine).skip(c);
                MongoCursor<Document> mongoCursor = findIterable.iterator();

                int size1 = 0;
                while (mongoCursor.hasNext()) {
                    Document next = mongoCursor.next();
                    if (size1 <= 0) {
                        for (String s : next.keySet()) {
                            list.add(s);
                        }
                        size1++;
                    }
                    LinkedList<String> colsArray;
                    for (String s : next.keySet()) {
                        Object o = next.get(s);
                        if (o == null) {
                            o = "";
                        }
                        colsArray = sourceDataMap.getOrDefault(s, new LinkedList<>());
                        colsArray.add(o.toString());
                        sourceDataMap.put(s, colsArray);


                    }
                }
                b++;
                c += 10;
            }

            logger.info("数据条数============>" + list.size());
        } catch (Exception e) {
            logger.error(e.getClass().getName() + ": " + e.getMessage());
        }finally {
            //mongoClient.close();
        }
        return sourceDataMap;
    }


    /**
     * 查询DB下的所有表名
     */
    public static List<String> getAllCollections(String host, int port, String username, String databaseName, String password) {
        MongoDatabase db = getDB(host, port, username, databaseName, password);
        MongoIterable<String> colls = getDB(host, port, username, databaseName, password).listCollectionNames();
        List<String> _list = new ArrayList<>();
        for (String s : colls) {
            MongoCollection<Document> coll = getDB(host, port, username, databaseName, password).getCollection(s);
            _list.add(s+coll);
        }

        return _list;
    }


    /**
     * 获取DB实例 - 指定DB
     *
     * @param databaseName
     * @return
     */
    public static MongoDatabase getDB(String host, int port, String username, String databaseName, String password) {
        MongoClient mongoClient = getMongoClient(host, port, username, databaseName, password);
        if (databaseName != null && !"".equals(databaseName)) {
            MongoDatabase database = mongoClient.getDatabase(databaseName);

            return database;
        }
        return null;
    }


    /**
     * 分页查询
     */
    public MongoCursor<Document> findByPage(MongoCollection<Document> coll, Bson filter, int pageNo, int pageSize) {
        Bson orderBy = new BasicDBObject("_id", 1);
        return coll.find(filter).sort(orderBy).skip((pageNo - 1) * pageSize).limit(pageSize).iterator();
    }


    /**
     * @desc 关闭mongo客户端连接
     */
    public static void close() {
        mongoClient.close();
    }


    public static void main(String[] args) {
        // MongoDB的服务器地址
        String host = "10.26.18.67";
        // MongoDB的服务器端口号
        int port = 27017;
        // MongoDB的服务器连接数据库名称
        String databaseName = "test";
        String username = "gexl";
        String password = "sc.9102";
        String collectionName = "userss";
        Map<String, Object> documentMap = new HashMap<String, Object>();
//        documentMap.put("id", 1);
//        documentMap.put("name", "aa");
//        documentMap.put("sex", "男");
//        documentMap.put("address", "深圳");
        //  List<String> tableNames = getAllCollections(host,port,username,databaseName,password);
        Map tableNamess = findAlls(host, port, username, databaseName, password, collectionName);
    }

}
